#pragma once

#include <iostream>
#include <string>
#include <cassert>
#include <functional>
#include "Epoll.hpp"
#include "Sock.hpp"
#include "log.hpp"

const static int gport = 8000;
using func_t = std::function<std::string(std::string)>;

class EpollServer
{
    const static int gnum = 64; // 最大事务数

public:
    EpollServer(func_t func, uint16_t port = gport)
        : _func(func), _port(port)
    {
    }

    void InitServer()
    {
        _listenSock.Socket();
        _listenSock.Bind(_port);
        _listenSock.Listen();
        _epoller.Create();
    }

    void Start()
    {
        bool r = _epoller.AddEvent(_listenSock.Fd(), EPOLLIN); // 将listensock添加到epoll中
        assert(r);                                             // 确保事件操作成功
        (void)r;                                               // 消除未使用变量编译器警告

        int timeout = -1;
        while (true)
        {
            int n = _epoller.Wait(_revs, gnum, timeout);
            switch (n)
            {
            case 0:
                logMessage(Debug, "timeout...");
                break;
            case -1:
                logMessage(Warning, "epoll_wait failed");
                break;
            default:
                logMessage(Debug, "有%d个事件就绪了", n);
                HandlerEvents(n);
                break;
            }
        }
    }

    void HandlerEvents(int num)
    {
        for (int i = 0; i < num; i++)
        {
            int fd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            if (events & EPOLLIN) // 有数据可读
            {
                if (fd == _listenSock.Fd())
                {
                    // 新连接到来
                    std::string clientip;
                    uint16_t clientport;
                    int sock = _listenSock.Accept(&clientip, &clientport);

                    bool r = _epoller.AddEvent(_listenSock.Fd(), EPOLLIN); // 将listensock添加到epoll中
                    assert(r);                                             // 确保事件操作成功
                    (void)r;                                               // 消除未使用变量编译器警告
                }
                else // 普通读取事件
                {
                    // 此处无法保证读到一个完整的报文，报文由应用层协议规定。实质就是没有应用层协议
                    char request[1024];
                    ssize_t s = recv(fd, request, sizeof(request) - 1, 0);
                    if (s > 0)
                    {
                        request[s - 1] = 0; // \r\n
                        request[s - 2] = 0; // \r\n

                        std::string response = _func(request);

                        send(fd, response.c_str(), response.size(), 0);
                    }
                    else
                    {
                        if (s == 0)
                            logMessage(Info, "client quit ...");
                        else
                            logMessage(Warning, "recv error, client quit ...");
                        // 在处理异常的时候，先从epoll中移除，然后再关闭
                        _epoller.DelEvent(fd);
                        close(fd);
                    }
                }
            }
        }
    }

    ~EpollServer()
    {
        _listenSock.Close();
        _epoller.Close();
    }

private:
    uint16_t _port;                 // 端口号
    Sock _listenSock;               // 监听套接字
    Epoller _epoller;               // epoll多路IO
    struct epoll_event _revs[gnum]; // 数组内存放事务
    func_t _func;
};